/**
*	@file AST.cpp
*
*	@brief this header file is defining the AST structure
*
*	@author li yuchen
*
*	@date 1/28/2011
*/

#include "AST.h"
#include "Utility.h"
using namespace std;
#include <iostream>

TNode* AST::p_tnode_AST_root_ = CreateTNode(ROOT,NOT_APPLICABLE,NOT_APPLICABLE);

TNode* AST::CreateTNode(TNodeType type, TNodeValue value, StmtNum stmt_num){
	TNode* new_tnode = new TNode;
	new_tnode->type = type;
	new_tnode->value = value;
	new_tnode->stmt_num = stmt_num;

	new_tnode->child = NULL;
	new_tnode->parent = NULL;
	new_tnode->left_sibling = NULL;
	new_tnode->right_sibling = NULL;
	return new_tnode;
}

void AST::SetParent(TNode* parent, TNode* child){
	if(parent == NULL || child == NULL){
		cout << "TNode is NULL, press key to exit!" << endl;
		getchar();
		exit(1);
	}
	parent->child = child;
	child->parent = parent;
}

void AST::SetSibling(TNode* left, TNode* right){
	if(left == NULL || right == NULL){
		cout << "TNode is NULL, press a key to exit!" << endl;
		getchar();
		exit(1);
	}

	left->right_sibling = right;
	right->left_sibling = left;

	// create the up link for the right sibling
	right->parent = left->parent;
}

 bool AST::IsPatternMatch(TNode* assign_tnode,VarIdx modifies_var_idx,TNode* right_pattern,bool is_relaxed){
	 if(modifies_var_idx == 0 && right_pattern == NULL) return true;

	 // check left modifies variable
	 if(modifies_var_idx != 0)
		 if(assign_tnode->child->value != modifies_var_idx) return false; 
	 if(assign_tnode->type == ASSIGN_TYPE){	
		if(right_pattern == NULL) return true;
		if(is_relaxed){
			return AST::RelaxedPatternMatch(assign_tnode->child->right_sibling,right_pattern);
		}
		else{
			return AST::StrictPatternMatch(assign_tnode->child->right_sibling,right_pattern);
		}
	 }
	 else if(assign_tnode->type == WHILE_TYPE || assign_tnode->type == IF_TYPE) return true;
	 else{
	 // for query optimizer
		 return StrictPatternMatch(assign_tnode,right_pattern);
	 }
}

bool AST::StrictPatternMatch(TNode* expr_root,TNode* pattern_root){
	if(expr_root == NULL && pattern_root == NULL) return true;
	if(expr_root == NULL) return false;
	else if(pattern_root == NULL) return false;
	if(expr_root->type != pattern_root->type || expr_root->value != pattern_root->value) return false;

	if(!AST::StrictPatternMatch(expr_root->child,pattern_root->child)) return false;
	if(expr_root->child == NULL && pattern_root->child == NULL) return true;
	if(expr_root->child == NULL) return false;
	else if(pattern_root->child == NULL) return false;

	return AST::StrictPatternMatch(expr_root->child->right_sibling,pattern_root->child->right_sibling);
}

bool AST::RelaxedPatternMatch(TNode* expr_root,TNode* pattern_root){
	//if(expr_root == NULL && pattern_root == NULL) return false;
	if(AST::StrictPatternMatch(expr_root,pattern_root)) return true;
	
	if(expr_root->child == NULL) return false;
	if(AST::RelaxedPatternMatch(expr_root->child,pattern_root)) return true;

	return AST::RelaxedPatternMatch(expr_root->child->right_sibling,pattern_root);
}